/*
 *   Licensed to the Apache Software Foundation (ASF) under one
 *   or more contributor license agreements.  See the NOTICE file
 *   distributed with this work for additional information
 *   regarding copyright ownership.  The ASF licenses this file
 *   to you under the Apache License, Version 2.0 (the
 *   "License"); you may not use this file except in compliance
 *   with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing,
 *   software distributed under the License is distributed on an
 *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *   KIND, either express or implied.  See the License for the
 *   specific language governing permissions and limitations
 *   under the License.
 */

package com.mystnihon.freeremote.util;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.Header;
import org.apache.http.client.HttpClient;
import org.apache.http.message.BasicNameValuePair;

import android.content.Context;
import android.text.TextUtils;
import android.util.Base64;

import com.mystnihon.freeremote.util.NetworkConnection.HttpMethod;

public class NetworkConnectionRequest {

    // Application context used to create http client if not set
    public Context context = null;

    // User Agent used to create a http client if it is not set
    public String userAgent = null;

    // Url of the request
    public String url = null;

    public HttpMethod method = HttpMethod.Get;

    public List<BasicNameValuePair> parameters = null;

    public String postText = null;

    public ArrayList<Header> headers = null;

    public boolean isGzipEnabled = false;

    // Set the using http client
    public HttpClient client = null;

    public boolean checkResponse = true;
    public boolean checkLocationChanged = false;

    // File to store the result data
    // Use to not store in file but return result
    public String storeResultFile = null;

    // False to not read http response and return object in response without closing http client
    // The response object is set in the NetworkConnectionResponse
    public boolean readHttpResponse = true;

    //
    // Ctr
    //
    // There is a lot of method to help on the retro compatibility
    //

    public NetworkConnectionRequest(String url) {
        this.url = url;
    }

    public NetworkConnectionRequest(Context ctx, String url, HttpMethod method) {
        context = ctx;
        this.url = url;
        this.method = method;
    }

    public NetworkConnectionRequest(Context ctx, String url, HttpMethod method, List<BasicNameValuePair> parameters) {
        context = ctx;
        this.url = url;
        this.method = method;
        this.parameters = parameters;
    }

    public NetworkConnectionRequest(Context ctx, String url, HttpMethod method, List<BasicNameValuePair> parameters, ArrayList<Header> headers, boolean isGzipEnabled) {
        context = ctx;
        this.url = url;
        this.method = method;
        this.parameters = parameters;
        this.headers = headers;
        this.isGzipEnabled = isGzipEnabled;
    }

    public NetworkConnectionRequest(Context ctx, String url, HttpMethod method, List<BasicNameValuePair> parameters, ArrayList<Header> headers, boolean isGzipEnabled, String userAgent) {
        context = ctx;
        this.url = url;
        this.method = method;
        this.parameters = parameters;
        this.headers = headers;
        this.isGzipEnabled = isGzipEnabled;
        this.userAgent = userAgent;
    }

    public NetworkConnectionRequest(Context ctx, String url, HttpMethod method, String postText, List<BasicNameValuePair> parameters, ArrayList<Header> headers, boolean isGzipEnabled, String userAgent) {
        context = ctx;
        this.url = url;
        this.method = method;
        this.postText = postText;
        this.parameters = parameters;
        this.headers = headers;
        this.isGzipEnabled = isGzipEnabled;
        this.userAgent = userAgent;
    }

    public NetworkConnectionRequest(Context ctx, String url, HttpMethod method, String postText, List<BasicNameValuePair> parameters, ArrayList<Header> headers, boolean isGzipEnabled,
            String userAgent, boolean checkResponse) {
        context = ctx;
        this.url = url;
        this.method = method;
        this.postText = postText;
        this.parameters = parameters;
        this.headers = headers;
        this.isGzipEnabled = isGzipEnabled;
        this.checkResponse = checkResponse;
        this.userAgent = userAgent;
    }

    public NetworkConnectionRequest(HttpClient client, String url, HttpMethod method, String postText, List<BasicNameValuePair> parameters, ArrayList<Header> headers, boolean isGzipEnabled,
            boolean checkResponse) {
        this.client = client;
        this.url = url;
        this.method = method;
        this.postText = postText;
        this.parameters = parameters;
        this.headers = headers;
        this.isGzipEnabled = isGzipEnabled;
        this.checkResponse = checkResponse;
    }

    public NetworkConnectionRequest(Context ctx, String url, HttpMethod method, String postText, List<BasicNameValuePair> parameters, ArrayList<Header> headers, boolean isGzipEnabled,
            String userAgent, boolean checkResponse, boolean checkLocationChanged) {
        context = ctx;
        this.url = url;
        this.method = method;
        this.postText = postText;
        this.parameters = parameters;
        this.headers = headers;
        this.isGzipEnabled = isGzipEnabled;
        this.checkResponse = checkResponse;
        this.userAgent = userAgent;
        this.checkLocationChanged = checkLocationChanged;
    }

    //
    // Accessor
    //

    public boolean hasToStoreResultInFile() {
        return !TextUtils.isEmpty(storeResultFile);
    }

    public void addHeader(Header header) {
        if (headers == null)
            headers = new ArrayList<Header>();

        headers.add(header);
    }

    private String cacheKey = null;

    public String getCacheKey() {
        if (cacheKey == null) {
            StringBuilder builder = new StringBuilder(url);
            if (parameters != null && parameters.size() > 0) {
                for (int i = 0; i < parameters.size(); i++) {
                    final BasicNameValuePair b = parameters.get(i);
                    // simple concat in order to build cache key. well not serve for request
                    builder.append(b.getName()).append(b.getValue());
                }
            }
            builder.append(postText);
            try {
                cacheKey = SHA1(builder.toString());
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
                cacheKey = url;
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                cacheKey = url;
            }
            
        }
        return cacheKey;
    }

    private static String convertToHex(byte[] data) {
        StringBuilder buf = new StringBuilder();
        for (byte b : data) {
            int halfbyte = (b >>> 4) & 0x0F;
            int two_halfs = 0;
            do {
                buf.append((0 <= halfbyte) && (halfbyte <= 9) ? (char) ('0' + halfbyte) : (char) ('a' + (halfbyte - 10)));
                halfbyte = b & 0x0F;
            } while (two_halfs++ < 1);
        }
        return buf.toString();
    }

    public static String SHA1(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        md.update(text.getBytes("UTF-8"), 0, text.length());
        byte[] sha1hash = md.digest();
        return convertToHex(sha1hash);
    }
}
